package org.yunai.swjg.server.module.quest.vo;

import com.alibaba.fastjson.JSON;
import org.yunai.swjg.server.entity.DoingQuestEntity;
import org.yunai.swjg.server.module.idSequence.IdSequenceHolder;
import org.yunai.swjg.server.module.player.vo.Player;
import org.yunai.swjg.server.module.quest.AbstractQuest;
import org.yunai.swjg.server.module.quest.QuestDef;
import org.yunai.swjg.server.module.quest.condition.IQuestCondition;
import org.yunai.swjg.server.rpc.message.S_C.S_C_QuestUpdateResp;
import org.yunai.swjg.server.rpc.struct.StQuestInfo;
import org.yunai.yfserver.persistence.PersistenceObject;
import org.yunai.yfserver.util.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 玩家正在进行中的任务
 * User: yunai
 * Date: 13-5-9
 * Time: 下午7:46
 */
public class DoingQuest implements PersistenceObject<Integer, DoingQuestEntity> {

    /**
     * 编号
     */
    private Integer id;
    /**
     * 玩家信息
     */
    private Player player;
    /**
     * 任务
     */
    private AbstractQuest quest;
    /**
     * 接受任务时间, 单位：毫秒
     */
    private Long acceptTime;
    /**
     * 完成条件集合
     */
    private Map<QuestDef.Condition, Map<Integer, Integer>> finishedConditions;
    /**
     * 是否在数据库中
     */
    private boolean inDB;

    private DoingQuest() {
    }

    public Integer getPlayerId() {
        return player.getId();
    }

    public AbstractQuest getQuest() {
        return quest;
    }

    public Long getAcceptTime() {
        return acceptTime;
    }

    @Override
    public Integer getId() {
        return id;
    }

    @Override
    public boolean isInDB() {
        return inDB;
    }

    @Override
    public void setInDB(boolean inDB) {
        this.inDB = inDB;
    }

    @Override
    public Integer getUnitId() {
        return player.getId();
    }

    @Override
    public void fromEntity(DoingQuestEntity entity) {
        id = entity.getId();
        finishedConditions = new HashMap<>(QuestDef.Condition.values().length);
        acceptTime = entity.getAcceptTime();
        String propsStr = entity.getProps();
        if (!StringUtils.isEmpty(propsStr)) {
            List<DoingQuestEntity.Prop> props = JSON.parseArray(entity.getProps(), DoingQuestEntity.Prop.class);
            for (DoingQuestEntity.Prop prop : props) {
                Map<Integer, Integer> subConditions = finishedConditions.get(QuestDef.Condition.valueOf(prop.getType()));
                if (subConditions == null) {
                    finishedConditions.put(QuestDef.Condition.valueOf(prop.getType()), subConditions = new HashMap<>(1));
                }
                subConditions.put(prop.getSubject(), prop.getCount());
            }
        }
    }

    @Override
    public DoingQuestEntity toEntity() {
        DoingQuestEntity entity = new DoingQuestEntity();
        entity.setId(id);
        entity.setPlayerId(player.getId());
        entity.setQuestId(quest.getId());
        entity.setAcceptTime(acceptTime);
        if (finishedConditions.size() > 0) {
            List<DoingQuestEntity.Prop> props = new ArrayList<>(finishedConditions.size());
            for (Map.Entry<QuestDef.Condition, Map<Integer, Integer>> entry : finishedConditions.entrySet()) {
                for (Map.Entry<Integer, Integer> subEntry : entry.getValue().entrySet()) {
                    props.add(new DoingQuestEntity.Prop(entry.getKey().getIndex(), subEntry.getKey(), subEntry.getValue()));
                }
            }
            if (props.size() > 0) {
                entity.setProps(JSON.toJSONString(props));
            } else {
                entity.setProps("");
            }
        } else {
            entity.setProps("");
        }
        return entity;
    }

    // ==================== 业务方法BEGIN ====================
    public static DoingQuest build(Player player, DoingQuestEntity entity, AbstractQuest quest) {
        DoingQuest doingQuest = new DoingQuest();
        doingQuest.inDB = true;
        doingQuest.player = player;
        doingQuest.quest = quest;
        doingQuest.fromEntity(entity);
        return doingQuest;
    }

    public static DoingQuest save(Player player, AbstractQuest quest, Long acceptTime) {
        DoingQuest doingQuest = new DoingQuest();
        doingQuest.inDB = false;
        doingQuest.id = IdSequenceHolder.genDoingQuestId();
        doingQuest.player = player;
        doingQuest.quest = quest;
        doingQuest.acceptTime = acceptTime;
        doingQuest.finishedConditions = new HashMap<>(QuestDef.Condition.values().length);
        for (IQuestCondition condition : quest.getFinishConditions()) {
            Map<Integer, Integer> subConditions = doingQuest.finishedConditions.get(condition.getCondition());
            if (subConditions == null) {
                doingQuest.finishedConditions.put(condition.getCondition(), subConditions = new HashMap<>(1));
            }
            subConditions.put(condition.getSubject(), condition.initParam(player));
        }
        player.save(doingQuest);
        return doingQuest;
    }

    /**
     * 获得完成任务条件某个主体的完成数量
     *
     * @param condition 完成条件
     * @param subject   主体
     * @return 完成数量
     */
    public Integer getFinishedCount(QuestDef.Condition condition, Integer subject) {
        Map<Integer, Integer> subConditions = finishedConditions.get(condition);
        if (subConditions == null) {
            return 0;
        }
        Integer count = subConditions.get(subject);
        return count != null ? count : null;
    }

    /**
     * 判断完成条件是否包含某个主体的要求
     *
     * @param condition 完成条件类型
     * @param subject   主体
     * @return true/false
     */
    public boolean containFinishedCondition(QuestDef.Condition condition, Integer subject) {
        Map<Integer, Integer> subConditions = finishedConditions.get(condition);
        return subConditions != null && subConditions.containsKey(subject);
    }

    public void changeFinishedCount(QuestDef.Condition condition, Integer subject, Integer count) {
        if (count <= 0) {
            return;
        }
        Map<Integer, Integer> subConditions = finishedConditions.get(condition);
        if (subConditions == null || !subConditions.containsKey(subject)) {
            return;
        }
        // 修改入库
        subConditions.put(subject, count);
        player.save(this);
        // 通知客户端任务的变化
        StQuestInfo questInfo = quest.genDoingQuestInfo(player, this);
        player.message(new S_C_QuestUpdateResp(questInfo));
    }
}
